﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace TowerDefense
{
    public class Location : IComparable
    {
        private int row; // row location in grid
        private int col; // column location in grid
        //Thomas first commit
        //Zak first commit
        // yo quiero uno taco
        //Alex says that he's the coolest person ever
        //Jordan
        //Evans Commit
        //Ryans commit
        //Zack H commit

        /**
         * The turn angle for turning 90 degrees to the left.
         */
        public static readonly int LEFT = -90;
        /**
         * The turn angle for turning 90 degrees to the right.
         */
        public static readonly int RIGHT = 90;
        /**
         * The turn angle for turning 45 degrees to the left.
         */
        public static readonly int HALF_LEFT = -45;
        /**
         * The turn angle for turning 45 degrees to the right.
         */
        public static readonly int HALF_RIGHT = 45;
        /**
         * The turn angle for turning a full circle.
         */
        public static readonly int FULL_CIRCLE = 360;
        /**
         * The turn angle for turning a half circle.
         */
        public static readonly int HALF_CIRCLE = 180;
        /**
         * The turn angle for making no turn.
         */
        public static readonly int AHEAD = 0;

        /**
         * The compass direction for north.
         */
        public static readonly int NORTH = 0;
        /**
         * The compass direction for northeast.
         */
        public static readonly int NORTHEAST = 45;
        /**
         * The compass direction for east.
         */
        public static readonly int EAST = 90;
        /**
         * The compass direction for southeast.
         */
        public static readonly int SOUTHEAST = 135;
        /**
         * The compass direction for south.
         */
        public static readonly int SOUTH = 180;
        /**
         * The compass direction for southwest.
         */
        public static readonly int SOUTHWEST = 225;
        /**
         * The compass direction for west.
         */
        public static readonly int WEST = 270;
        /**
         * The compass direction for northwest.
         */
        public static readonly int NORTHWEST = 315;

        /**
         * Constructs a location with given row and column coordinates.
         * @param r the row
         * @param c the column
         */
        public Location(int r, int c)
        {
            row = r;
            col = c;
        }

        /**
         * Gets the row coordinate.
         * @return the row of this location
         */
        public int getRow()
        {
            return row;
        }

        /**
         * Gets the column coordinate.
         * @return the column of this location
         */
        public int getCol()
        {
            return col;
        }

        public Vector2 GetLocation()
        {
            //TODO: Modify the location returned from the grid to be in correct relation to screen, i.e multiply each by the proper factor
            return new Vector2(row, col);
        }

        /**
         * Gets the adjacent location in any one of the eight compass directions.
         * @param direction the direction in which to find a neighbor location
         * @return the adjacent location in the direction that is closest to
         * <tt>direction</tt>
         */
        public Location getAdjacentLocation(int direction)
        {
            // reduce mod 360 and round to closest multiple of 45
            int adjustedDirection = (direction + HALF_RIGHT / 2) % FULL_CIRCLE;
            if (adjustedDirection < 0)
                adjustedDirection += FULL_CIRCLE;

            adjustedDirection = (adjustedDirection / HALF_RIGHT) * HALF_RIGHT;
            int dc = 0;
            int dr = 0;
            if (adjustedDirection == EAST)
                dc = 1;
            else if (adjustedDirection == SOUTHEAST)
            {
                dc = 1;
                dr = 1;
            }
            else if (adjustedDirection == SOUTH)
                dr = 1;
            else if (adjustedDirection == SOUTHWEST)
            {
                dc = -1;
                dr = 1;
            }
            else if (adjustedDirection == WEST)
                dc = -1;
            else if (adjustedDirection == NORTHWEST)
            {
                dc = -1;
                dr = -1;
            }
            else if (adjustedDirection == NORTH)
                dr = -1;
            else if (adjustedDirection == NORTHEAST)
            {
                dc = 1;
                dr = -1;
            }
            return new Location(getRow() + dr, getCol() + dc);
        }

        /**
         * Returns the direction from this location toward another location. The
         * direction is rounded to the nearest compass direction.
         * @param target a location that is different from this location
         * @return the closest compass direction from this location toward
         * <code>target</code>
         */
        public int getDirectionToward(Location target)
        {
            int dx = target.getCol() - getCol();
            int dy = target.getRow() - getRow();
            // y axis points opposite to mathematical orientation

            int angle = (int)((360 / Math.PI) * (Math.Atan2(-dy, dx)));

            // mathematical angle is counterclockwise from x-axis,
            // compass angle is clockwise from y-axis
            int compassAngle = RIGHT - angle;
            // prepare for truncating division by 45 degrees
            compassAngle += HALF_RIGHT / 2;
            // wrap negative angles
            if (compassAngle < 0)
                compassAngle += FULL_CIRCLE;
            // round to nearest multiple of 45
            return (compassAngle / HALF_RIGHT) * HALF_RIGHT;
        }

        /**
         * Indicates whether some other <code>Location</code> object is "equal to"
         * this one.
         * @param other the other location to test
         * @return <code>true</code> if <code>other</code> is a
         * <code>Location</code> with the same row and column as this location;
         * <code>false</code> otherwise
         */
        public bool equals(Object other)
        {
            if ((other != typeof(Location)))
                return false;

            Location otherLoc = (Location)other;
            return getRow() == otherLoc.getRow() && getCol() == otherLoc.getCol();
        }

        /**
         * Generates a hash code.
         * @return a hash code for this location
         */
        public int hashCode()
        {
            return getRow() * 3737 + getCol();
        }

        /**
         * Compares this location to <code>other</code> for ordering. Returns a
         * negative integer, zero, or a positive integer as this location is less
         * than, equal to, or greater than <code>other</code>. Locations are
         * ordered in row-major order. <br />
         * (Precondition: <code>other</code> is a <code>Location</code> object.)
         * @param other the other location to test
         * @return a negative integer if this location is less than
         * <code>other</code>, zero if the two locations are equal, or a positive
         * integer if this location is greater than <code>other</code>
         */

        /**
         * Creates a string that describes this location.
         * @return a string with the row and column of this location, in the format
         * (row, col)
         */
        public String toString()
        {
            return "(" + getRow() + ", " + getCol() + ")";
        }

        public int CompareTo(object obj)
        {
            Location otherLoc = (Location)obj;
            if (getRow() < otherLoc.getRow())
                return -1;
            if (getRow() > otherLoc.getRow())
                return 1;
            if (getCol() < otherLoc.getCol())
                return -1;
            if (getCol() > otherLoc.getCol())
                return 1;
            return 0;
        }
    }
}
